﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using ZilLion.Service.Core.Infrastructure.Middleware.WebSocket.Interface;

namespace ZilLion.Service.Core.Infrastructure.Middleware.WebSocket
{
    /// <summary>
    /// websocket 消息处理
    /// </summary>
    public abstract class WebSocketHandler: IWebSocketHandler
    {
        private readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };

        private WebSocketConnectionManager _webSocketConnectionManager;

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="webSocketConnectionManager"></param>
        protected WebSocketHandler(WebSocketConnectionManager webSocketConnectionManager)
        {
            WebSocketConnectionManager = webSocketConnectionManager;
        }

        protected WebSocketConnectionManager WebSocketConnectionManager
        {
            get { return _webSocketConnectionManager; }
            set { _webSocketConnectionManager = value; }
        }


        public virtual  async Task ReceiveAsync(System.Net.WebSockets.WebSocket socket, WebSocketReceiveResult result,
            string messageJson)
        {
            var Message =
                JsonConvert.DeserializeObject<SocketMessage>(messageJson);


            if (Message != null && Message.MessageType.IsNotNullOrEmpty())
            {

            }

            //var method = GetType().GetMethod(invocationDescriptor.MethodName);

            //if (method == null)
            //{
            //    await SendMessageAsync(socket, new SocketMessage
            //    {
            //        MessageType = MessageType.Text,
            //        Data = $"Cannot find method {invocationDescriptor.MethodName}"
            //    }).ConfigureAwait(false);
            //    return;
            //}

            try
            {
                //method.Invoke(this, invocationDescriptor.Arguments);
                await SendMessageAsync(socket, new SocketMessage
                {
                    MessageType = "TEST",
                    Data = $"testststs"
                }).ConfigureAwait(false);

            }
            catch (TargetParameterCountException)
            {
                //await SendMessageAsync(socket, new SocketMessage
                //{
                //    MessageType = MessageType.Text,
                //    Data =
                //        $"The {invocationDescriptor.MethodName} method does not take {invocationDescriptor.Arguments.Length} parameters!"
                //}).ConfigureAwait(false);
            }

            catch (ArgumentException)
            {
                //await SendMessageAsync(socket, new SocketMessage
                //{
                //    MessageType = MessageType.Text,
                //    Data = $"The {invocationDescriptor.MethodName} method takes different arguments!"
                //}).ConfigureAwait(false);
            }
        }

        #region 链接操作
        /// <inheritdoc />
        public virtual async Task OnConnected(System.Net.WebSockets.WebSocket socket)
        {
            WebSocketConnectionManager.AddSocket(socket);

            await SendMessageAsync(socket, new SocketMessage
            {
                MessageId = Guid.NewGuid().ToString("N"),
                MessageType = SocketMessageType.CLINET_CONNECTED,
                Data = WebSocketConnectionManager.GetId(socket)
            }).ConfigureAwait(false);
        }

        /// <inheritdoc />
        public virtual async Task OnDisconnected(System.Net.WebSockets.WebSocket socket)
        {
            await WebSocketConnectionManager.RemoveSocket(WebSocketConnectionManager.GetId(socket))
                .ConfigureAwait(false);
        }

        #endregion

        #region 消息发送
        /// <inheritdoc />
        public async Task SendMessageAsync(System.Net.WebSockets.WebSocket socket, SocketMessage socketMessage)
        {
            if (socket.State != WebSocketState.Open)
                return;

            var serializedMessage = JsonConvert.SerializeObject(socketMessage, _jsonSerializerSettings);
            var encodedMessage = Encoding.UTF8.GetBytes(serializedMessage);
            await socket.SendAsync(new ArraySegment<byte>(encodedMessage,
                    0,
                    encodedMessage.Length),
                WebSocketMessageType.Text,
                true,
                CancellationToken.None).ConfigureAwait(false);
        }
        /// <inheritdoc />
        public async Task SendMessageAsync(string socketId, SocketMessage socketMessage)
        {
            await SendMessageAsync(WebSocketConnectionManager.GetSocketById(socketId), socketMessage).ConfigureAwait(false);
        }
        /// <inheritdoc />
        public async Task SendMessageToAllAsync(SocketMessage socketMessage)
        {
            foreach (var pair in WebSocketConnectionManager.GetAll())
                if (pair.Value.State == WebSocketState.Open)
                    await SendMessageAsync(pair.Value, socketMessage).ConfigureAwait(false);
        }


        /// <inheritdoc />
        public async Task SendMessageToGroupAsync(string groupId, SocketMessage socketMessage)
        {
            var sockets = WebSocketConnectionManager.GetAllFromGroup(groupId);
            if (sockets != null)
                foreach (var socket in sockets)
                    await SendMessageAsync(socket, socketMessage);
        }


        /// <inheritdoc />
        public async Task SendMessageToGroupAsync(string groupId, SocketMessage socketMessage, IList<string> exceptgroupId)
        {
            var sockets = WebSocketConnectionManager.GetAllFromGroup(groupId);
            if (sockets != null)
                foreach (var id in sockets)
                    if (exceptgroupId.All(x => x != id))
                        await SendMessageAsync(id, socketMessage);
        }

        #endregion
    }
}